package syssv

import (
	"context"
	"database/sql"
	"encoding/json"
	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
	"strconv"
	"strings"
	"time"
	"wzgames/internal/admin/adc"
	"wzgames/internal/admin/admindao"
	"wzgames/internal/constant"
	"wzgames/internal/gloader"
	"wzgames/internal/model/gamep"
	"wzgames/internal/model/mcomm"
	"wzgames/internal/response"
	"wzgames/pkg/logger"
	"wzgames/pkg/utils/byteutil"
	"wzgames/pkg/utils/dateutil"
)

func (sv *SysSV) PublishCurrToCache(adm *adc.Admin) int16 {
	dao := admindao.SysDao{Driver: sv.adminDs.Ds()}
	ret, err := dao.GetCurrencyList("", 0, 0, 0)
	if err != nil {
		if err != sql.ErrNoRows {
			logger.Error("[SysSV] push currency to cache Error on GetCurrencyList", zap.Int64("AdminId", adm.AdminId()), zap.Error(err))
			return response.ErrInternal
		}
	}

	if ret == nil || len(ret) == 0 {
		return 0
	}

	currs := &mcomm.SysCurrencies{
		DataList:  make(map[string]*mcomm.SysCurrency),
		CurrIdMap: make(map[int32]string),
	}
	for _, c := range ret {
		currs.DataList[c.Curr] = &mcomm.SysCurrency{
			CurrID:    c.CurrId,
			Curr:      c.Curr,
			CurrType:  c.CurrType,
			Status:    c.Status,
			Precision: c.Precision,
		}
		currs.CurrIdMap[c.CurrId] = c.Curr
	}

	b, err1 := proto.Marshal(currs)
	if err1 != nil {
		logger.Error("[SysSV] push currency to cache Error on proto.Marshal", zap.Int64("AdminId", adm.AdminId()), zap.Error(err1))
		return response.ErrInternal
	}
	_, err = gloader.CClient().Store(constant.CcCommRoot+"/currency", byteutil.SliceByteToString(b))
	if err != nil {
		logger.Error("[SysSV] push currency to cache Error on cache store", zap.Int64("AdminId", adm.AdminId()), zap.Error(err))
		return response.ErrInternal
	}

	return 0
}

func (sv *SysSV) PublishSysGameToCache(adm *adc.Admin, gameId int32) int16 {
	dao := admindao.GameDao{Driver: sv.adminDs.Ds()}
	ret, err := dao.GetSysGameById(gameId)
	if err != nil {
		if err != sql.ErrNoRows {
			logger.Error("[SysSV] push sys game to cache Error on GetSysGameById", zap.Int64("AdminId", adm.AdminId()), zap.Int32("GameId", gameId), zap.Error(err))
			return response.ErrInternal
		}
	}

	if ret == nil || ret.GameId == 0 {
		return response.ErrNotFound
	}

	arr := strings.Split(ret.Langs, ",")
	langs := make(map[string]string)
	for _, v := range arr {
		langs[v] = v
	}

	gm := &gamep.WzGame{
		GameID:   ret.GameId,
		GameName: ret.Name,
		Tag:      ret.GTag,
		Status:   ret.Status,
		Langs:    langs,
		Grp:      ret.Grp,
		Updated:  dateutil.UnixSecs(),
	}

	b, err1 := proto.Marshal(gm)
	if err1 != nil {
		logger.Error("[SysSV] push sys game to cache Error on proto.Marshal", zap.Int64("AdminId", adm.AdminId()), zap.Int32("GameId", gameId), zap.Error(err1))
		return response.ErrInternal
	}
	_, err = gloader.CClient().Store(constant.CcBaseRoot+"/games/"+gm.Tag, byteutil.SliceByteToString(b))
	if err != nil {
		logger.Error("[SysSV] push sys game to cache Error on cache store", zap.Int64("AdminId", adm.AdminId()), zap.Int32("GameId", gameId), zap.Error(err))
		return response.ErrInternal
	}

	return 0
}

func (sv *SysSV) PublishSysGameCurrToCache(adm *adc.Admin, gcId int64) int16 {
	dao := admindao.SysDao{Driver: sv.adminDs.Ds()}
	ret, err := dao.GetGameCurrencyById(gcId)
	if err != nil {
		if err != sql.ErrNoRows {
			logger.Error("[SysSV] push sys game currency to cache Error on GetGameCurrencyById", zap.Int64("AdminId", adm.AdminId()), zap.Int64("GcId", gcId), zap.Error(err))
			return response.ErrInternal
		}
	}

	if ret == nil || ret.GcId == 0 {
		return response.ErrNotFound
	}

	gm := &gamep.GameCurrency{
		GcID:            gcId,
		GameID:          ret.GameId,
		CurrID:          ret.CurrId,
		Curr:            ret.Curr,
		Status:          ret.Status,
		VType:           ret.VType,
		Updated:         dateutil.UnixSecs(),
		FloatValueLimit: nil,
		StrValueLimit:   nil,
	}
	if ret.VType == mcomm.ValueType_Float64Type {
		item := &gamep.GameCurrencyLimit{}
		err = json.Unmarshal(byteutil.StringToSliceByte(ret.Cfg), item)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return response.ErrInternal
		}
		gm.FloatValueLimit = item
	} else {
		itemStr := &gamep.GameCurrencyLimitStr{}
		err = json.Unmarshal(byteutil.StringToSliceByte(ret.Cfg), itemStr)
		if err != nil {
			//logger.Error("err == ", zap.String("error", err.Error()))
			return response.ErrInternal
		}
		gm.StrValueLimit = itemStr
	}

	b, err1 := proto.Marshal(gm)
	if err1 != nil {
		logger.Error("[SysSV] push sys game currency to cache Error on proto.Marshal", zap.Int64("AdminId", adm.AdminId()), zap.Int64("GcId", gcId), zap.Error(err1))
		return response.ErrInternal
	}
	var bd strings.Builder
	bd.WriteString(gloader.EnvString())
	bd.WriteString(constant.CacheGameCurrKey)
	bd.WriteString(strconv.FormatInt(gcId, 10))
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
	_, err = gloader.CommMgr().RedisPool().Get().SetEx(ctx, bd.String(), b, dateutil.Day*time.Second).Result()
	cancel()
	if err != nil {
		logger.Error("[SysSV] push sys game currency to cache Error on cache store", zap.Int64("AdminId", adm.AdminId()), zap.Int64("GcId", gcId), zap.Error(err))
		return response.ErrInternal
	}

	return 0
}
